2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../jucer_Headers.h"
27 #include "../model/jucer_JucerDocument.h"
30 //==============================================================================
31 const String
replaceCEscapeChars (const String
& s
)
33 const int len
= s
.length();
36 r
.preallocateBytes (4 * len
+ 4);
37 bool lastWasHexEscapeCode
= false;
39 for (int i
= 0; i
< len
; ++i
)
41 const juce_wchar c
= s
[i
];
47 lastWasHexEscapeCode
= false;
51 lastWasHexEscapeCode
= false;
55 lastWasHexEscapeCode
= false;
59 lastWasHexEscapeCode
= false;
63 lastWasHexEscapeCode
= false;
67 lastWasHexEscapeCode
= false;
72 ! (lastWasHexEscapeCode
73 && String ("0123456789abcdefABCDEF").containsChar (c
))) // (have to avoid following a hex escape sequence with a valid hex digit)
76 lastWasHexEscapeCode
= false;
80 lastWasHexEscapeCode
= true;
81 r
<< "\\x" << String::toHexString ((int) c
);
91 const String
quotedString (const String
& s
)
94 return "String::empty";
96 const int embeddedIndex
= s
.indexOfIgnoreCase ("%%");
98 if (embeddedIndex
>= 0)
100 String
s1 (s
.substring (0, embeddedIndex
));
101 String
s2 (s
.substring (embeddedIndex
+ 2));
104 const int closeIndex
= s2
.indexOf ("%%");
108 code
= s2
.substring (0, closeIndex
).trim();
109 s2
= s2
.substring (closeIndex
+ 2);
112 if (code
.isNotEmpty())
117 result
<< quotedString (s1
) << " + ";
122 result
<< " + " << quotedString (s2
);
128 return "L\"" + replaceCEscapeChars (s
) + "\"";
131 const String
replaceStringTranslations (String s
, JucerDocument
* document
)
133 s
= s
.replace ("%%getName()%%", document
->getComponentName());
134 s
= s
.replace ("%%getButtonText()%%", document
->getComponentName());
139 const String
castToFloat (const String
& expression
)
141 if (expression
.containsOnly ("0123456789.f"))
143 String
s (expression
.getFloatValue());
145 if (s
.containsChar ('.'))
151 return "(float) (" + expression
+ ")";
154 const String
indentCode (const String
& code
, const int numSpaces
)
159 const String
space (String::repeatedString (" ", numSpaces
));
162 lines
.addLines (code
);
164 for (int i
= 1; i
< lines
.size(); ++i
)
166 String
s (lines
[i
].trimEnd());
173 return lines
.joinIntoString ("\n");
176 //==============================================================================
177 const String
makeValidCppIdentifier (String s
,
178 const bool capitalise
,
179 const bool removeColons
,
180 const bool allowTemplates
)
183 s
= s
.replaceCharacters (".,;:/@", "______");
185 s
= s
.replaceCharacters (".,;/@", "_____");
188 for (i
= s
.length(); --i
> 0;)
189 if (CharacterFunctions::isLetter (s
[i
])
190 && CharacterFunctions::isLetter (s
[i
- 1])
191 && CharacterFunctions::isUpperCase (s
[i
])
192 && ! CharacterFunctions::isUpperCase (s
[i
- 1]))
193 s
= s
.substring (0, i
) + " " + s
.substring (i
);
195 String
allowedChars ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ 0123456789");
197 allowedChars
+= "<>";
203 words
.addTokens (s
.retainCharacters (allowedChars
), false);
211 for (i
= 1; i
< words
.size(); ++i
)
213 if (capitalise
&& words
[i
].length() > 1)
214 n
<< words
[i
].substring (0, 1).toUpperCase()
215 << words
[i
].substring (1).toLowerCase();
220 if (CharacterFunctions::isDigit (n
[0]))
223 // make sure it's not a reserved c++ keyword..
224 static const char* const reservedWords
[] =
226 "auto", "const", "double", "float", "int", "short", "struct",
227 "return", "static", "union", "while", "asm", "dynamic_cast",
228 "unsigned", "break", "continue", "else", "for", "long", "signed",
229 "switch", "void", "case", "default", "enum", "goto", "register",
230 "sizeof", "typedef", "volatile", "char", "do", "extern", "if",
231 "namespace", "reinterpret_cast", "try", "bool", "explicit", "new",
232 "static_cast", "typeid", "catch", "false", "operator", "template",
233 "typename", "class", "friend", "private", "this", "using", "const_cast",
234 "inline", "public", "throw", "virtual", "delete", "mutable", "protected",
235 "true", "wchar_t", "and", "bitand", "compl", "not_eq", "or_eq",
236 "xor_eq", "and_eq", "bitor", "not", "or", "xor", "cin", "endl",
237 "INT_MIN", "iomanip", "main", "npos", "std", "cout", "include",
238 "INT_MAX", "iostream", "MAX_RAND", "NULL", "string"
241 for (i
= 0; i
< numElementsInArray (reservedWords
); ++i
)
242 if (n
== reservedWords
[i
])
248 //==============================================================================
249 int indexOfLineStartingWith (const StringArray
& lines
, const String
& text
, int startIndex
)
251 startIndex
= jmax (0, startIndex
);
253 while (startIndex
< lines
.size())
255 if (lines
[startIndex
].trimStart().startsWithIgnoreCase (text
))
264 //==============================================================================
265 const String
valueToFloat (const double v
)
267 String
s ((double) (float) v
, 4);
269 if (s
.containsChar ('.'))
277 const String
boolToString (const bool b
)
279 return b
? "true" : "false";
282 //==============================================================================
283 const String
colourToHex (const Colour
& col
)
285 return String::toHexString ((int) col
.getARGB());
288 //==============================================================================
289 const String
colourToCode (const Colour
& col
)
291 #define COL(col) Colours::col,
293 const Colour colours
[] =
295 #include "jucer_Colours.h"
296 Colours::transparentBlack
300 #define COL(col) #col,
301 static const char* colourNames
[] =
303 #include "jucer_Colours.h"
308 for (int i
= 0; i
< numElementsInArray (colourNames
) - 1; ++i
)
309 if (col
== colours
[i
])
310 return "Colours::" + String (colourNames
[i
]);
312 return "Colour (0x" + colourToHex (col
) + ")";
315 void setColourXml (XmlElement
& xml
, const char* const attName
, const Colour
& colour
)
317 xml
.setAttribute (attName
, colourToHex (colour
));
320 const Colour
getColourXml (const XmlElement
& xml
, const char* const attName
, const Colour
& defaultColour
)
322 return Colour (xml
.getStringAttribute (attName
, colourToHex (defaultColour
)).getHexValue32());
325 //==============================================================================
326 const String
positionToString (const RelativePositionedRectangle
& pos
)
329 toks
.addTokens (pos
.rect
.toString(), false);
331 return toks
[0] + " " + toks
[1];
334 void positionToXY (const RelativePositionedRectangle
& position
,
335 double& x
, double& y
,
336 const Rectangle
<int>& parentArea
,
337 const ComponentLayout
* layout
)
340 position
.getRectangleDouble (x
, y
, w
, h
, parentArea
, layout
);
343 void positionToCode (const RelativePositionedRectangle
& position
,
344 const ComponentLayout
* layout
,
345 String
& x
, String
& y
, String
& w
, String
& h
)
347 // these are the code sections for the positions of the relative comps
348 String xrx
, xry
, xrw
, xrh
;
349 Component
* const relCompX
= layout
!= 0 ? layout
->findComponentWithId (position
.relativeToX
) : 0;
351 positionToCode (ComponentTypeHandler::getComponentPosition (relCompX
), layout
, xrx
, xry
, xrw
, xrh
);
353 String yrx
, yry
, yrw
, yrh
;
354 Component
* const relCompY
= layout
!= 0 ? layout
->findComponentWithId (position
.relativeToY
) : 0;
356 positionToCode (ComponentTypeHandler::getComponentPosition (relCompY
), layout
, yrx
, yry
, yrw
, yrh
);
358 String wrx
, wry
, wrw
, wrh
;
359 Component
* const relCompW
= (layout
!= 0 && position
.rect
.getWidthMode() != PositionedRectangle::absoluteSize
)
360 ? layout
->findComponentWithId (position
.relativeToW
) : 0;
362 positionToCode (ComponentTypeHandler::getComponentPosition (relCompW
), layout
, wrx
, wry
, wrw
, wrh
);
364 String hrx
, hry
, hrw
, hrh
;
365 Component
* const relCompH
= (layout
!= 0 && position
.rect
.getHeightMode() != PositionedRectangle::absoluteSize
)
366 ? layout
->findComponentWithId (position
.relativeToH
) : 0;
368 positionToCode (ComponentTypeHandler::getComponentPosition (relCompH
), layout
, hrx
, hry
, hrw
, hrh
);
371 if (position
.rect
.getWidthMode() == PositionedRectangle::proportionalSize
)
373 if (wrw
.isNotEmpty())
374 w
<< "roundFloatToInt ((" << wrw
<< ") * " << valueToFloat (position
.rect
.getWidth()) << ")";
376 w
<< "proportionOfWidth (" << valueToFloat (position
.rect
.getWidth()) << ")";
378 else if (position
.rect
.getWidthMode() == PositionedRectangle::parentSizeMinusAbsolute
)
380 if (wrw
.isNotEmpty())
381 w
<< "(" << wrw
<< ") - " << roundToInt (position
.rect
.getWidth());
383 w
<< "getWidth() - " << roundToInt (position
.rect
.getWidth());
387 if (wrw
.isNotEmpty())
388 w
<< "(" << wrw
<< ") + ";
390 w
<< roundToInt (position
.rect
.getWidth());
394 if (position
.rect
.getHeightMode() == PositionedRectangle::proportionalSize
)
396 if (hrh
.isNotEmpty())
397 h
<< "roundFloatToInt ((" << hrh
<< ") * " << valueToFloat (position
.rect
.getHeight()) << ")";
399 h
<< "proportionOfHeight (" << valueToFloat (position
.rect
.getHeight()) << ")";
401 else if (position
.rect
.getHeightMode() == PositionedRectangle::parentSizeMinusAbsolute
)
403 if (hrh
.isNotEmpty())
404 h
<< "(" << hrh
<< ") - " << roundToInt (position
.rect
.getHeight());
406 h
<< "getHeight() - " << roundToInt (position
.rect
.getHeight());
410 if (hrh
.isNotEmpty())
411 h
<< "(" << hrh
<< ") + ";
413 h
<< roundToInt (position
.rect
.getHeight());
417 if (position
.rect
.getPositionModeX() == PositionedRectangle::proportionOfParentSize
)
419 if (xrx
.isNotEmpty() && xrw
.isNotEmpty())
420 x
<< "(" << xrx
<< ") + roundFloatToInt ((" << xrw
<< ") * " << valueToFloat (position
.rect
.getX()) << ")";
422 x
<< "proportionOfWidth (" << valueToFloat (position
.rect
.getX()) << ")";
424 else if (position
.rect
.getPositionModeX() == PositionedRectangle::absoluteFromParentTopLeft
)
426 if (xrx
.isNotEmpty())
427 x
<< "(" << xrx
<< ") + ";
429 x
<< roundToInt (position
.rect
.getX());
431 else if (position
.rect
.getPositionModeX() == PositionedRectangle::absoluteFromParentBottomRight
)
433 if (xrx
.isNotEmpty())
434 x
<< "(" << xrx
<< ") + (" << xrw
<< ")";
438 const int d
= roundToInt (position
.rect
.getX());
442 else if (position
.rect
.getPositionModeX() == PositionedRectangle::absoluteFromParentCentre
)
444 if (xrx
.isNotEmpty())
445 x
<< "(" << xrx
<< ") + (" << xrw
<< ") / 2";
447 x
<< "(getWidth() / 2)";
449 const int d
= roundToInt (position
.rect
.getX());
456 if (position
.rect
.getAnchorPointX() == PositionedRectangle::anchorAtRightOrBottom
)
458 else if (position
.rect
.getAnchorPointX() == PositionedRectangle::anchorAtCentre
)
459 x
<< " - ((" << w
<< ") / 2)";
463 if (position
.rect
.getPositionModeY() == PositionedRectangle::proportionOfParentSize
)
465 if (yry
.isNotEmpty() && yrh
.isNotEmpty())
466 y
<< "(" << yry
<< ") + roundFloatToInt ((" << yrh
<< ") * " << valueToFloat (position
.rect
.getY()) << ")";
468 y
<< "proportionOfHeight (" << valueToFloat (position
.rect
.getY()) << ")";
470 else if (position
.rect
.getPositionModeY() == PositionedRectangle::absoluteFromParentTopLeft
)
472 if (yry
.isNotEmpty())
473 y
<< "(" << yry
<< ") + ";
475 y
<< roundToInt (position
.rect
.getY());
477 else if (position
.rect
.getPositionModeY() == PositionedRectangle::absoluteFromParentBottomRight
)
479 if (yry
.isNotEmpty())
480 y
<< "(" << yry
<< ") + (" << yrh
<< ")";
484 const int d
= roundToInt (position
.rect
.getY());
488 else if (position
.rect
.getPositionModeY() == PositionedRectangle::absoluteFromParentCentre
)
490 if (yry
.isNotEmpty())
491 y
<< "(" << yry
<< ") + (" << yrh
<< ") / 2";
493 y
<< "(getHeight() / 2)";
495 const int d
= roundToInt (position
.rect
.getY());
502 if (position
.rect
.getAnchorPointY() == PositionedRectangle::anchorAtRightOrBottom
)
504 else if (position
.rect
.getAnchorPointY() == PositionedRectangle::anchorAtCentre
)
505 y
<< " - ((" << h
<< ") / 2)";
509 const String
justificationToCode (const Justification
& justification
)
511 switch (justification
.getFlags())
513 case Justification::centred
:
514 return "Justification::centred";
516 case Justification::centredLeft
:
517 return "Justification::centredLeft";
519 case Justification::centredRight
:
520 return "Justification::centredRight";
522 case Justification::centredTop
:
523 return "Justification::centredTop";
525 case Justification::centredBottom
:
526 return "Justification::centredBottom";
528 case Justification::topLeft
:
529 return "Justification::topLeft";
531 case Justification::topRight
:
532 return "Justification::topRight";
534 case Justification::bottomLeft
:
535 return "Justification::bottomLeft";
537 case Justification::bottomRight
:
538 return "Justification::bottomRight";
540 case Justification::left
:
541 return "Justification::left";
543 case Justification::right
:
544 return "Justification::right";
546 case Justification::horizontallyCentred
:
547 return "Justification::horizontallyCentred";
549 case Justification::top
:
550 return "Justification::top";
552 case Justification::bottom
:
553 return "Justification::bottom";
555 case Justification::verticallyCentred
:
556 return "Justification::verticallyCentred";
558 case Justification::horizontallyJustified
:
559 return "Justification::horizontallyJustified";
566 return "Justification (" + String (justification
.getFlags()) + ")";
569 //==============================================================================
570 void drawResizableBorder (Graphics
& g
,
572 const BorderSize
<int> borderSize
,
573 const bool isMouseOver
)
575 g
.setColour (Colours::orange
.withAlpha (isMouseOver
? 0.4f
: 0.3f
));
577 g
.fillRect (0, 0, w
, borderSize
.getTop());
578 g
.fillRect (0, 0, borderSize
.getLeft(), h
);
579 g
.fillRect (0, h
- borderSize
.getBottom(), w
, borderSize
.getBottom());
580 g
.fillRect (w
- borderSize
.getRight(), 0, borderSize
.getRight(), h
);
582 g
.drawRect (borderSize
.getLeft() - 1, borderSize
.getTop() - 1,
583 w
- borderSize
.getRight() - borderSize
.getLeft() + 2,
584 h
- borderSize
.getTop() - borderSize
.getBottom() + 2);
587 void drawMouseOverCorners (Graphics
& g
, int w
, int h
)
589 RectangleList
r (Rectangle
<int> (0, 0, w
, h
));
590 r
.subtract (Rectangle
<int> (1, 1, w
- 2, h
- 2));
592 const int size
= jmin (w
/ 3, h
/ 3, 12);
593 r
.subtract (Rectangle
<int> (size
, 0, w
- size
- size
, h
));
594 r
.subtract (Rectangle
<int> (0, size
, w
, h
- size
- size
));
596 g
.setColour (Colours::darkgrey
);
598 for (int i
= r
.getNumRectangles(); --i
>= 0;)
599 g
.fillRect (r
.getRectangle (i
));
604 //==============================================================================
605 RelativePositionedRectangle::RelativePositionedRectangle()
613 RelativePositionedRectangle::RelativePositionedRectangle (const RelativePositionedRectangle
& other
)
615 relativeToX (other
.relativeToX
),
616 relativeToY (other
.relativeToY
),
617 relativeToW (other
.relativeToW
),
618 relativeToH (other
.relativeToH
)
622 RelativePositionedRectangle
& RelativePositionedRectangle::operator= (const RelativePositionedRectangle
& other
)
625 relativeToX
= other
.relativeToX
;
626 relativeToY
= other
.relativeToY
;
627 relativeToW
= other
.relativeToW
;
628 relativeToH
= other
.relativeToH
;
632 RelativePositionedRectangle::~RelativePositionedRectangle()
636 //==============================================================================
637 bool RelativePositionedRectangle::operator== (const RelativePositionedRectangle
& other
) const throw()
639 return rect
== other
.rect
640 && relativeToX
== other
.relativeToX
641 && relativeToY
== other
.relativeToY
642 && relativeToW
== other
.relativeToW
643 && relativeToH
== other
.relativeToH
;
646 bool RelativePositionedRectangle::operator!= (const RelativePositionedRectangle
& other
) const throw()
648 return ! operator== (other
);
651 void RelativePositionedRectangle::getRelativeTargetBounds (const Rectangle
<int>& parentArea
,
652 const ComponentLayout
* layout
,
653 int& x
, int& xw
, int& y
, int& yh
,
654 int& w
, int& h
) const
663 rx
= layout
->findComponentWithId (relativeToX
);
664 ry
= layout
->findComponentWithId (relativeToY
);
665 rw
= layout
->findComponentWithId (relativeToW
);
666 rh
= layout
->findComponentWithId (relativeToH
);
669 x
= parentArea
.getX() + (rx
!= 0 ? rx
->getX() : 0);
670 y
= parentArea
.getY() + (ry
!= 0 ? ry
->getY() : 0);
671 w
= rw
!= 0 ? rw
->getWidth() : parentArea
.getWidth();
672 h
= rh
!= 0 ? rh
->getHeight() : parentArea
.getHeight();
673 xw
= rx
!= 0 ? rx
->getWidth() : parentArea
.getWidth();
674 yh
= ry
!= 0 ? ry
->getHeight() : parentArea
.getHeight();
677 const Rectangle
<int> RelativePositionedRectangle::getRectangle (const Rectangle
<int>& parentArea
,
678 const ComponentLayout
* layout
) const
680 int x
, xw
, y
, yh
, w
, h
;
681 getRelativeTargetBounds (parentArea
, layout
, x
, xw
, y
, yh
, w
, h
);
683 const Rectangle
<int> xyRect ((xw
<= 0 || yh
<= 0) ? Rectangle
<int>()
684 : rect
.getRectangle (Rectangle
<int> (x
, y
, xw
, yh
)));
686 const Rectangle
<int> whRect ((w
<= 0 || h
<= 0) ? Rectangle
<int>()
687 : rect
.getRectangle (Rectangle
<int> (x
, y
, w
, h
)));
689 return Rectangle
<int> (xyRect
.getX(), xyRect
.getY(),
690 whRect
.getWidth(), whRect
.getHeight());
693 void RelativePositionedRectangle::getRectangleDouble (double& x
, double& y
, double& w
, double& h
,
694 const Rectangle
<int>& parentArea
,
695 const ComponentLayout
* layout
) const
697 int rx
, rxw
, ry
, ryh
, rw
, rh
;
698 getRelativeTargetBounds (parentArea
, layout
, rx
, rxw
, ry
, ryh
, rw
, rh
);
700 double dummy1
, dummy2
;
701 rect
.getRectangleDouble (Rectangle
<int> (rx
, ry
, rxw
, ryh
), x
, y
, dummy1
, dummy2
);
702 rect
.getRectangleDouble (Rectangle
<int> (rx
, ry
, rw
, rh
), dummy1
, dummy2
, w
, h
);
705 void RelativePositionedRectangle::updateFromComponent (const Component
& comp
,
706 const ComponentLayout
* layout
)
708 int x
, xw
, y
, yh
, w
, h
;
709 getRelativeTargetBounds (Rectangle
<int> (0, 0, comp
.getParentWidth(), comp
.getParentHeight()),
710 layout
, x
, xw
, y
, yh
, w
, h
);
712 PositionedRectangle
xyRect (rect
), whRect (rect
);
713 xyRect
.updateFrom (comp
.getBounds(), Rectangle
<int> (x
, y
, xw
, yh
));
714 whRect
.updateFrom (comp
.getBounds(), Rectangle
<int> (x
, y
, w
, h
));
716 rect
.setX (xyRect
.getX());
717 rect
.setY (xyRect
.getY());
718 rect
.setWidth (whRect
.getWidth());
719 rect
.setHeight (whRect
.getHeight());
722 void RelativePositionedRectangle::updateFrom (double newX
, double newY
, double newW
, double newH
,
723 const Rectangle
<int>& parentArea
, const ComponentLayout
* layout
)
725 int x
, xw
, y
, yh
, w
, h
;
726 getRelativeTargetBounds (parentArea
, layout
, x
, xw
, y
, yh
, w
, h
);
728 PositionedRectangle
xyRect (rect
), whRect (rect
);
729 xyRect
.updateFromDouble (newX
, newY
, newW
, newH
, Rectangle
<int> (x
, y
, xw
, yh
));
730 whRect
.updateFromDouble (newX
, newY
, newW
, newH
, Rectangle
<int> (x
, y
, w
, h
));
732 rect
.setX (xyRect
.getX());
733 rect
.setY (xyRect
.getY());
734 rect
.setWidth (whRect
.getWidth());
735 rect
.setHeight (whRect
.getHeight());
738 void RelativePositionedRectangle::applyToXml (XmlElement
& e
) const
740 e
.setAttribute ("pos", rect
.toString());
742 if (relativeToX
!= 0)
743 e
.setAttribute ("posRelativeX", String::toHexString (relativeToX
));
744 if (relativeToY
!= 0)
745 e
.setAttribute ("posRelativeY", String::toHexString (relativeToY
));
746 if (relativeToW
!= 0)
747 e
.setAttribute ("posRelativeW", String::toHexString (relativeToW
));
748 if (relativeToH
!= 0)
749 e
.setAttribute ("posRelativeH", String::toHexString (relativeToH
));
752 void RelativePositionedRectangle::restoreFromXml (const XmlElement
& e
,
753 const RelativePositionedRectangle
& defaultPos
)
755 rect
= PositionedRectangle (e
.getStringAttribute ("pos", defaultPos
.rect
.toString()));
756 relativeToX
= e
.getStringAttribute ("posRelativeX", String::toHexString (defaultPos
.relativeToX
)).getHexValue64();
757 relativeToY
= e
.getStringAttribute ("posRelativeY", String::toHexString (defaultPos
.relativeToY
)).getHexValue64();
758 relativeToW
= e
.getStringAttribute ("posRelativeW", String::toHexString (defaultPos
.relativeToW
)).getHexValue64();
759 relativeToH
= e
.getStringAttribute ("posRelativeH", String::toHexString (defaultPos
.relativeToH
)).getHexValue64();